/**
 * Copyright (C) 2009 Noel Ang
 *
 * This file is part of Samsara.
 *
 * Samsara is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Samsara is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Samsara.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package com.lunarshades.samsara.ui.actions;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.prefs.Preferences;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import com.lunarshades.samsara.Raider;
import com.lunarshades.samsara.ui.RosterTableModel;
import com.lunarshades.samsara.ui.SamsaraFrame;

/**
 * Action for saving data to a file store.
 *
 * @author Noel Ang, sparta.variable@gmail.com
 * @see com.lunarshades.samsara.ui.RosterTableModel
 */
public class SaveDataAction<E extends Raider> extends AbstractAction
        implements PropertyChangeListener {

public SaveDataAction(RosterTableModel<E> pModel, SamsaraFrame pAppFrame) {
    super(NAME);
    mApp = pAppFrame;
    mModel = pModel;

    URL smallIconUrl = getClass().getResource(
            "/com/lunarshades/samsara/ui/icons/save16.gif"
    );
    putValue(Action.SMALL_ICON, new ImageIcon(smallIconUrl));
    putValue(Action.SHORT_DESCRIPTION, SHORT_TEXT);
    putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S);
    setEnabled(false);

    mFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
    mFileChooser.setMultiSelectionEnabled(false);
}

private File chooseFile() {
    File targetFile = null;
    int decision = mFileChooser.showSaveDialog(mApp);
    if (decision == JFileChooser.APPROVE_OPTION) {
        targetFile = mFileChooser.getSelectedFile();
    }
    return targetFile;
}

private boolean saveData() {
    File targetFile = mFileStore;
    boolean success = false;

    if (targetFile == null) {
        targetFile = chooseFile();
    }
    if (targetFile != null) {
        if (saveData(targetFile)) {
            success = true;
            setEnabled(!success);
            mFileStore = targetFile;
            mApp.postStatusMessage(MessageFormat.format(FILE_SAVED_STATUS,
                    targetFile.getName()
            )
            );
            firePropertyChange(FILE_SAVED, null, targetFile);
        }
    }
    return success;
}

private boolean saveData(File pTargetFile) {
    final String LINE_SEPARATOR = System.getProperty("line.separator");
    boolean isFileSaved = true;
    BufferedWriter writer = null;
    try {
        FileWriter out = new FileWriter(pTargetFile);
        writer = new BufferedWriter(out);

        synchronized (mModel) {
            for (Raider raider : mModel.sortedSet()) {
                // Exclude pick-ups
                if (raider.pickup()) {
                    continue;
                }
                writer.write(raider.marshal());
                writer.write(LINE_SEPARATOR);
            }
        }
    } catch (IOException e) {
        isFileSaved = false;
        e.printStackTrace(System.err);
        StringBuffer messageBuffer = new StringBuffer();
        messageBuffer.append("Data could not be saved!\n");
        messageBuffer.append(e.getLocalizedMessage());
        JOptionPane.showMessageDialog(mApp,
                messageBuffer.toString(),
                "Save canceled",
                JOptionPane.ERROR_MESSAGE
        );
    } finally {
        if (writer != null) {
            try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace(System.err);
            }
        }
    }
    return (isFileSaved);
}

void setFileStore(File pStore) {
    mFileStore = pStore;
}

File getFileStore() {
    return mFileStore;
}

public boolean execute() {
    return saveData();
}

public void savePreferences(Preferences pPrefs) {
    pPrefs.put(PREF_CWD, mFileChooser.getCurrentDirectory().getPath()
    );
}

public void loadPreferences(Preferences pPrefs) {
    String startingDirectory = mFileChooser.getCurrentDirectory().getPath();
    String currentDirectory = pPrefs.get(PREF_CWD, startingDirectory);
    if (!currentDirectory.equals(startingDirectory)) {
        File currentFile = new File(currentDirectory);
        if (currentFile.isFile()) {
            currentFile = currentFile.getParentFile();
        }
        if (currentFile != null && currentFile.isDirectory()) {
            mFileChooser.setCurrentDirectory(currentFile);
        }
    }
}

public void actionPerformed(ActionEvent ignored) {
    saveData();
}

public void propertyChange(PropertyChangeEvent evt) {
    String property = evt.getPropertyName();
    if (evt.getSource() == mApp) {
        if (SamsaraFrame.DATA_MODIFIED.equals(property)) {
            setEnabled(true);
        } else if (SamsaraFrame.DATA_CLEAN.equals(property)) {
            setEnabled(false);
        }
    } else if (LoadDataAction.FILE_LOADED.equals(property)) {
        setEnabled(false);
        Object store = evt.getNewValue();
        if (store instanceof File) {
            setFileStore((File) store);
        }
    } else if (RosterImportAction.DATA_IMPORTED.equals(property)) {
        setFileStore(null);
        setEnabled(true);
    }
}

private static final String NAME = "Save";
private static final String SHORT_TEXT = "Save the current data set to file";
private static final String PREF_CWD = "CurrentSaveDirectory";
private static final String FILE_SAVED_STATUS = "Saved {0}.";
private final SamsaraFrame mApp;
private final RosterTableModel<E> mModel;
private final JFileChooser mFileChooser = new JFileChooser();
private volatile File mFileStore;

public static final String FILE_SAVED = "FileSaved";
}
